/**
 * Foxit Software Inc.
 * Copyright(C) 2005-2014, all rights reserved.
 * The following code is copyrighted and contains proprietary information
 * and trade secrets of Foxit Software Inc.

 * Description: App class, responsible for the module management , event notification and view management.
 * Author: shaojie zhuo
 * Update: shaojie zhuo (2014-05-07 11:12)
 */

define(function (require, exports, module) {
    var EventList = WebPDF.EventList = require('./EventList')
    var Environment = WebPDF.Environment = require('./Environment.js'); 
    var Config = WebPDF.Config = require('./Config.js');
    require('./Support.js');    
    require('./Math/Rect.js');
    require('./Math/Point.js');
    require('./Math/JSMap.js');
    require('./Math/Matrix.js');
    var CommonDialog = require('./CommonDialog.js');
    require('./Tools/Tools.js');
    require('./DataLevel.js');
    require('./PDFData/Dest.js');
    var MainView = require('./PDFView/MainView');
    var PDFDocView = require('./PDFView/PDFDocView.js');

    //Load HTML5::Canvas support javascript library
    if (!$.support.canvas) {
        require("./Cavans/uupaa-color.mini.js");
        require("./Cavans/uupaa-excanvas.js");
    }
    require('./Event/IMainFrmEventHandler');
    require('./Event/IMousePtHander');
    var HandToolHandler = require('./Tools/HandToolHandler');
    var CMenuItem = require('./MenuItem');   
    require("./PDFData/Text/TextManager");    
    /**
     * Enum for engine type of Reader
     * @enum {number}
     * @private
     */
    WebPDF.ReaderEngineType = {
        // Reader base on image.
        IMAGE: 0,
        // Reader base on HTML5.
        HTML5: 1
    };

    /**
     * Response code from server for PDF conversion.
     * @enum {Number}
     * @private
     */
    WebPDF.ConversionState = {
        // conversion successfully
        SUCCESS: 0,
        // conversion has been initialized
        INITIALIZE: 1,
        // conversion is in progress
        IN_PROGRESS: 2,
        // server is busy
        SERVICE_BUSY: 3,
        // conversion failed.
        CONVERSION_ERROR: 4,
        // unexpected error.
        UNKNOWN_ERROR: 5
    };

    /**
     * Detail error code for PDF conversion.
     * @enum {Number}
     * @private
     */
    WebPDF.PDFError =
    {
        /**
         * unknown error.
         * @constant
         */
        ERROR_UNKNOWN: -1,
        /**
         * success
         * @constant
         */
        ERROR_SUCCESS: 0,
        /**
         * Parse PDF file failed
         * @constant
         */
        ERROR_PDFPARSE_FILE: 1,

        /**
         * Format error
         * @constant
         */
        ERROR_PDFPARSE_FORMAT: 2,
        /**
         * PDF password error
         * @constant
         */
        ERROR_PDFPARSE_PASSWORD: 3,
        /**
         * Unsupported PDF security handler
         * @constant
         */
        ERROR_PDFPARSE_HANDLER: 4,
        /**
         * Unsupported PDF certificate
         * @constant
         */
        ERROR_PDFPARSE_CERT: 5,
        /**
         * Com error
         * @constant
         */
        ERROR_COM_CALL: 6,
        /**
         * exception
         * @constant
         */
        ERROR_EXCEPTION: 7,
        /**
         * Get Pages info error
         * @constant
         */
        ERROR_MANIFEST_GET_ERROR: 8,
        /**
         * Write data to file failed.
         * @constant
         */
        ERROR_FILE_WRITE_ERROR: 9,
        /**
         * Create images failed.
         */
        ERROR_CREATE_IMAGE_ERROR: 10,
        /**
         * Get text information failed.
         * @constant
         */
        ERROR_CREATE_TEXT_ERROR: 11,
        /**
         * Get text information failed.
         * @constant
         */
        ERROR_CREATE_PATH_ERROR: 12,
        /**
         * Page count exceed maximum value.
         * @constant
         */
        ERROR_PDFPARSE_PAGE_COUNT_EXCEED: 13,
        /**
         * load form information error.
         * @constant
         */
        ERROR_CREAT_FORM_INFO_ERROR: 14
    };
    
    /**
     * Detail error code for PDF operation.
     * @enum {Number}
     * @private
     */
    WebPDF.PDFOperationError =
    {
		/**
         * unknown error
         * @constant
         */
		ERROR_UNKNOWN: -1,
		/**
         * success
         * @constant
         */
		ERROR_SUCCESS: 0,
		/**
         * Requires the user to log in
         * @constant
         */
		ERROR_NEED_SIGN_IN: 1,
		/**
         * Save the signature data failed
         * @constant
         */
		ERROR_SAVE_SIGN_LIST: 2,
		/**
         * Delete the signature data failed
         * @constant
         */
		ERROR_DELETE_SIGN_LIST: 3,
		/**
         * Signature operation failed
         * @constant
         */
		ERROR_SIGNATURE_OPERATION: 4,
		/**
		 * server is busy
		 */
		ERROR_SERVICE_BUSY: 5,
		/**
		 * Save data is empty
		 */
		ERROR_SAVEDATA_Empty: 6
    };

    /**
     * @namespace
     * @memberOf WebPDF
     * @enum
     * @description enum for PDF document type.
     */
    WebPDF.PDFDocType = {
        /**
         * @description Normal PDF.
         * @type {Number}
         * @constant
         */
        PDF: 1,
        /**
         * @description Acroform PDF.
         * @type {Number}
         * @constant
         */
        FORM: 2,
        /**
         * @description XFA PDF.
         * @type {Number}
         * @constant
         */
        XFA: 3
    };

    /**
     *  Enum for PDF standard permission
     *  @enum {Number}
     *  @private
     */
    WebPDF.PDFPermission = {
        PER_PRINT_LIMITED: 0x0008
    };
    
    
    WebPDF.loginEmail = null;

    /**
     * @class Represents an app instance，all operations are invoked through an instance of this class.
     * @memberOf WebPDF
     * @constructor
     * @param {String} fileID File ID.
     * @param {String} fileName File name.
     * @param {String} mainFrameID ID of the mainframe element of the viewer.
     * @param {Objects} options Options of reader instance.
     * @param {String} leftPanelID ID of the navigation panel.
     * @param {WebPDF.IDocumentLoader} documentLoader Document loader object.
     * @param {WebPDF.IPageViewRender} pageViewRender Page view render object.
     * @return {WebPDF.ReaderApp} An App instance.
     */
    var ReaderApp = function (options, viewerContainerId, documentLoader, pageViewRender) {
        this.options = options;
       // var _fileId = fileID;
       // var _fileName = fileName;
        
        this.mainFrameID = viewerContainerId;
       // var _leftPanelID = leftPanelID;         
        this.pageViewRender = pageViewRender;
        this.documentLoader = documentLoader;      
        

        /* plugin list, the format is {PluginName: Plugin} */
        this.pluginList = {};
        /* mouse event handler list*/
        this.mousePtHandlerList = [];
        /* tool handler list, the format is {toolName: tool}*/
        this.toolHandlerList = {};
        /* current tool handler*/
        this.curToolHandler = null;
        /* mainframe event handler list*/
        var _mainFrameEventHandlerList = [];

        /* command list*/
//        var _commandList = {};
        /* command ui list*/
//        var _commandUIList = {};
        /* menu item list*/
        var _menuItemList = {};

        //var _canDownloadPDF = true;
        var _isTrail = false;
        var _sessionId = null;
        //var _docHash = "";

        var _sessionIdAuthHeader = "x-auth-token";
        var _docPermission = 0;
        var _isFirstTimeParse = true;

        var _textManager = null;       
        /**
         * JQuery object for error information div of password dialog.
         * @private
         */
        var _jqPasswordDlgErrorInfo = null;
        /**
         * PDF password
         * @private
         */
        var _currentPDFPassword = null;
        /**
         * Retry count remained for request document information.
         * @type {Number}
         * @private
         */
        var _retryCountForDocument = 0;

        /*
        * Whether the document has been loaded
        * */
        var _isDocLoaded = false;

        /**
         * 不拦截鼠标事件的元素样式列表
         * @type {Array}
         * @private
         */
        var _ignoreMouseEventClassList = [];
        
        _loadDocument = _.bind(_loadDocument, this);
        
         /**
         * Reparse PDF document by password
         * @param jqPassword JQuery object for password information div of password dialog.
         * @param jqErrInfo  JQuery object for error information div of password dialog.
         * @private
         */
        function _reparseDocByPassword(jqPassword, jqErrInfo) {
            _isFirstTimeParse = false;
            _currentPDFPassword = jqPassword.val();
            _currentPDFPassword = encodeURIComponent(_currentPDFPassword);
            _jqPasswordDlgErrorInfo = jqErrInfo;            
            WebPDF.endConfirmPassword();
            WebPDF.waiting(this, {});
            _loadDocument(_currentPDFPassword, false, Config.defaults.maxManifestRetryCount);
        }

       



       

        /**
         * Check whether the document has been loaded.
         * @returns {boolean} return true if the document has been loaded.
         * @ignore
         */
        this.isDocumentLoaded = function(){
            return this.isDocLoaded;
        };

        /**
         * Load document from server.
         * @param pdfPassword PDF document password.
         * @param {Boolean | null} isCheckPassword Whether the request is for checking password or parsing document.
         * @param retryCount Retry count remained for request document information from server.
         * @private
         */
        function _loadDocument(pdfPassword, isCheckPassword,  retryCountForDocument) {
                      
            var readerApp = this;
            /**
             * Callback for load document successfully.
             * @param {WebPDF.IPDFDocument} pdfDoc PDFDocument object.
             * @param response Response from server
             * @returns {Boolean} return True if create viewer successfully, otherwise return false.
             * @private
             */
            function _loadDocumentSuccessCallback(pdfDoc, response) {
                WebPDF.closeWaiting(readerApp);
                WebPDF.endConfirmPassword();
                readerApp.pageViewRender.setReaderApp(readerApp);
                if (!pdfDoc) {
                    WebPDF.alert(readerApp, null, i18n.t("ParseError.LoadError"));
                    return;
                }           
             
               // try {                            
                    readerApp.pdfDoc = pdfDoc;
                    readerApp.mainView = new MainView(viewerContainerId, pdfDoc, readerApp.pageViewRender, readerApp);
                    readerApp.onResize();
                    readerApp.bindMouseEvent();
                    readerApp.loadPlugins();                   
                    if (!readerApp.isDocumentCanBePrint() || readerApp.options.disablePrint) {
                        readerApp.disablePrint();
                    }
                    readerApp.isDocLoaded = true;
                    readerApp.trigger(WebPDF.EventList.DOCUMENT_LOADED, {});
                   // readerApp.trigger(WebPDF.EventList.DOCVIEW_PAGE_CHANGED, {oldIndex: -1, curIndex: readerApp.getDocView().getCurPageIndex()});
                    
               // }
               // catch (ex) {
                  //  console.error(ex);
                    //return false;
              //  }
                return true;
            }
            
            
            /**
             * callback for load document failed.
             * @param {Object} response Response from server.
             * @private
             */
            function _loadDocumentFailedCallback(repsonse) {
                if (!$.isPlainObject(repsonse) || typeof repsonse.error == 'undefined'
                    || typeof repsonse.status == 'undefined') {
                    WebPDF.alert(readerApp, null, i18n.t("ParseError.LoadError"));
                    WebPDF.closeWaiting(readerApp);
                }
                else {
                    var error = repsonse.error;
                    if (error != 0) {
                        if (error == WebPDF.PDFError.ERROR_PDFPARSE_PASSWORD) {
                            WebPDF.closeWaiting(readerApp);
                            WebPDF.confirmPassword(readerApp, null, i18n.t("ParseError.EnterPassword"), _reparseDocByPassword);
                            if (!_isFirstTimeParse) {
                                _jqPasswordDlgErrorInfo.html("<span style='color:red'>" + i18n.t("ParseError.PasswordIncorrect")
                                        + "</span>");
                            }
                        }
                        else {
                            var status = repsonse.status;
                            if (WebPDF.Common.isNeedRetry(status)) {                              
                                _.delay(_loadDocument, Config.defaults.requestRetryInterval, _currentPDFPassword, true,  retryCountForDocument--);    
                            }
                            else {
                                WebPDF.endConfirmPassword();
                                WebPDF.closeWaiting(readerApp);
                                _popupParserFailDlg(error, status);
                            }
                        }
                    }
                }
            }
            
            
            if (retryCountForDocument <= 0) {
                WebPDF.closeWaiting(readerApp);
                _popupParserFailDlg(WebPDF.PDFError.ERROR_UNKNOWN, WebPDF.ConversionState.SERVICE_BUSY);
                return;
            }
            readerApp.documentLoader.asyncLoadDocument(this, pdfPassword,isCheckPassword, _loadDocumentSuccessCallback, _loadDocumentFailedCallback);
        }

        /**
         * popup dialog for load document failed.
         * @param errType Error type
         * @param status Status
         * @private
         */
        function _popupParserFailDlg(errType, status) {
            var dlgTitle = null;
            var pdfError = WebPDF.PDFError;
            switch (errType) {
                case pdfError.ERROR_COM_CALL:
                case pdfError.ERROR_PDFPARSE_FILE:
                    WebPDF.alert(this,dlgTitle, i18n.t("ParseError.FailToOpen"));
                    break;
                case pdfError.ERROR_PDFPARSE_FORMAT:
                    WebPDF.alert(this,dlgTitle, i18n.t("ParseError.ErrFormat"));
                    break;
                case pdfError.ERROR_PDFPARSE_HANDLER:
                    WebPDF.alert(this,dlgTitle, i18n.t("ParseError.ErrHandle"));
                    break;
                case pdfError.ERROR_PDFPARSE_CERT:
                    WebPDF.alert(this,dlgTitle, i18n.t("ParseError.ErrCert"));
                    break;
                case pdfError.ERROR_PDFPARSE_PAGE_COUNT_EXCEED:
                    WebPDF.alert(this,dlgTitle, i18n.t("ParseError.ErrPage"));
                    break;
                case 10019:
                	WebPDF.alert(this,dlgTitle, i18n.t("ParseError.VistedPagesLimit"));
                	break;
                default:
                {
                    if (status == WebPDF.ConversionState.SERVICE_BUSY) {
                        WebPDF.alert(this,dlgTitle, i18n.t("ParseError.ServiceBusy"));
                    }
                    else {
                        WebPDF.alert(this,dlgTitle, i18n.t("ParseError.UnKnown") + status);
                    }
                }
                    break;
            }
        }
        
        /**
         * Save pdf modify to the server
         * @param {Function(Boolean,String)} doneHandler callback for load document successfully.
         * @example
         * 		function _saveCallBack(statusCode, docpath) {
		 *			if (statusCode == WebPDF.PDFOperationError.ERROR_SUCCESS) {
		 *				alert("new doc path:" + docpath);
		 *			} else {
		 *				alert("save signature failed: code " + statusCode);
		 *			}
		 *		}
         * 		WebPDF.ViewerInstance.savePDFModify(_saveCallBack);
         */
        this.savePDFModify = function(doneHandler) {
            var formPlug = this.pluginList[WebPDF.FormPluginName];
            if (!this.getDocView().isModified()) {
                if (! (formPlug && formPlug.isModifiedFormData())) {
                    return;
                }
            }
        	
        	if(!$.isFunction(doneHandler)){
                $.error("'doneHandler' must be function.");
                return;
            }

        	var saveData = {};
        	//获取表单模块所需保存数据
            if(formPlug && formPlug.isModifiedFormData()){
            	var data = formPlug.getFormData();
            	if (data) {
                    saveData.formXmlData = data;
            	}
			}
        	
        	//获取签名所需保存数据
        	var signPlug = this.pluginList[WebPDF.SignaturePluginName];
        	if(signPlug){
        		signPlug.getSignatureSaveData(saveData);
			}
        	
        	//获取annot所需保存数据
        	var annotPlug = this.pluginList[WebPDF.BASEANNOT_PLUGIN_NAME];
        	if(annotPlug && this.isEditable()){
        		var annotsData = annotPlug.getAnnotationDataToSave();
        		if (annotsData.length > 0) {
                    //解决IE8下使用原生JSON.stringify时会进行uncode编码导致中文字符发到服务器乱码问题 (使用下面的方法会导致json格式不合法)
                    //eval("var dataStr = '" + JSON.stringify(annotsData) + "';");
                  //  saveData += "annotsData&&" + escape(JSON.stringify(annotsData));
                    saveData.annotData = escape(JSON.stringify(annotsData));
        		}
			}
        	
        	if (saveData) {
        		_savePDFModify(saveData, doneHandler);
        	} else {
        		this.setModified(null, null, false);
        		doneHandler(WebPDF.PDFOperationError.ERROR_SAVEDATA_Empty);
        	}
        };
        
        function _savePDFModify(saveData, doneHandler) {
            var data = saveData;
            data.type = 1;
            data.s3Key = this.getFileID();
            data.formMode = _options.formMode;
            WebPDF.waiting(this, {});
            $.ajax({
                url: _options.url + "pdfOperation",
                dataType: 'json',
                type: 'POST',
                data: data,
                success: function (response) {
                    try {
                        if(response.error == WebPDF.PDFOperationError.ERROR_SUCCESS){
                            WebPDF.closeWaiting(this);
                            this.setModified(null, null, false);
                            doneHandler(response.error,response.desDocPath);
                        }else{
                        	WebPDF.closeWaiting(this);
                        	doneHandler(response.error);
                        }
                    }
                    catch (ex) {
                    	WebPDF.closeWaiting(this);
                    	doneHandler(WebPDF.PDFOperationError.ERROR_UNKNOWN);
                    }
                },
                error: function () {
                    WebPDF.closeWaiting(this);
                    doneHandler(WebPDF.PDFOperationError.ERROR_UNKNOWN);
                }
            });
        };

        /**
         * Check whether the document can be print
         * @returns {Boolean} Whether the document can be print.
         * @ignore
         */
        this.isDocumentCanBePrint = function () {
            return (_docPermission & WebPDF.PDFPermission.PER_PRINT_LIMITED) == 0;
        };

        this.isEditable = function(){
            return WebPDF.Config.Plugins.load.Edit;
        };
        /**
         * 获取当前app对应的url配置信息
         * @returns {{}}
         * @ignore
         */
        this.getUrlConfig = function(){
            return _urlConfig;
        };

        /**
         * 添加鼠标事件不被拦截的元素样式
         * @param {String|Array.<String>} ignoreClass
         * @ignore
         */
        this.addIgnoreMouseEventClass = function(ignoreClass){
            if ($.isArray(ignoreClass)){
                $.each(ignoreClass,function(n,value) {
                    this.addIgnoreMouseEventClass(value);
                });
            }else if(ignoreClass){
                _ignoreMouseEventClassList.push(ignoreClass);
            }
        };

        /**
         * 获取鼠标事件不被拦截的元素样式列表
         * @returns {Array}
         * @ignore
         */
        this.getIgnoreMouseEventClasses = function(){
            return _ignoreMouseEventClassList;
        };


        /**
         * Get id of current app instance.
         * @returns {String}
         * @ignore
         */
        this.getAppId = function(){
            return this.mainFrameID;
        };

        /**
         * Get id of mainframe.
         * @returns {String} id of mainframe.
         * @ignore
         */
        this.getMainFrameId = function(){
            return this.mainFrameID;
        };

        /**
         * Return options of current viewer instance.
         * @returns {Objects}
         */
        this.getOptions = function(){
            return this.options;
        };

        /**
         * Check whether use form mode to render document currently.
         * @returns {Boolean} return true if use form mode to render document currently.
         * @ignore
         */
        this.isFormMode = function(){
            return this.options.formMode;
        };

        this.getBaseUrl = function(){
            return this.options.baseUrl;
        };

        /**
         * Check whether current document is a form file, and the form plugin is enabled
         * @returns {Boolean} return true if current document is a form file, and the form plugin is enabled,
         * otherwise return false
         * @ignore
         */
        this.isForm = function(){
            var pluginsConfig = WebPDF.Config.Plugins.load;
            return this.isFormMode() && pluginsConfig.Form === true && this.getPDFDoc().getDocType() == WebPDF.PDFDocType.FORM;
        };

        /**
         * register base modules.
         * @ignore
         */
    this.registerBaseModule = function (callback) {
        var handTool = new HandToolHandler(this);
        this.registerToolHandler(handTool);      
        var self = this;
        var pluginsConfig = WebPDF.Config.Plugins.load;         
        if(!Environment.mobile){
            /*===begin PC===*/
            //register annotation plugin     
            
            var deferredAnnot  = {};        
            pluginsConfig.Annot = false;
            if (pluginsConfig.Annot === true) {
                 deferredAnnot = $.Deferred();
                 require.async('./Plugins/Annot/BaseAnnotPlugin.js', function(annotPluginModule){
                 self.registerPlugin(annotPluginModule);               
               }); 
               if (pluginsConfig.Edit === true) {
                   require.async(['./Plugins/Annot/CommentAnnotPlugin.js', 
                                  './Plugins/Annot/TypewriterAnnotPlugin.js',                                
                                  './Plugins/Annot/TextAnnotPlugin.js',
                                  './Plugins/Annot/DrawingAnnotPlugin.js'
                                 ], function(commentAnnotPluginModule, typewriterAnnotPluginModule,textAnnotPluginModule,drawingAnnotPluginModule){
                        self.registerPlugin(commentAnnotPluginModule);
                        self.registerPlugin(typewriterAnnotPluginModule);
                        self.registerPlugin(textAnnotPluginModule);
                        self.registerPlugin(drawingAnnotPluginModule);
                        deferredAnnot.resolve();
                    });                  
                }
                else{
                    deferredAnnot.resolve();
                }
            }
          
            
            var deferredFind = {};
            //register find tool plugin
            if (pluginsConfig.FindTool === true) {
                 deferredFind = $.Deferred();
                   require.async('./Plugins/FindTool/FindToolPlugin.js',function(findToolPluginModule){
                      self.registerPlugin(findToolPluginModule);
                      deferredFind.resolve();
                });              
            }
           
             var deferredNavigation  = {};  
            //register navigation panel plugin            
            if (pluginsConfig.NavigationPanel === true) {
                deferredNavigation = $.Deferred();
                var navigationPanelPluginModule = require.async('./Plugins/NavigationPanel/NavigationPanelPlugin.js',function(navigationPanelPluginModule){
                    self.registerPlugin(navigationPanelPluginModule);                    
                    //register bookmark plugin;
                    var deferredBookmark = {}
                    if (pluginsConfig.Bookmark === true) {
                        deferredBookmark = $.Deferred();
                        require.async('./Plugins/Bookmark/BookmarkPlugin.js', function(bookmarkPluginModule){
                            self.registerPlugin(bookmarkPluginModule);
                             deferredBookmark.resolve();
                        });       
                    }                   
                    var deferredThumbnail = {};
                     //register thumbnail plugin
                    if (pluginsConfig.Thumbnail === true) {
                        deferredThumbnail = $.Deferred();
                        var thumbnailPluginModule = require.async('./Plugins/Thumbnail/ThumbNailPlugin.js', function(thumbnailPluginModule){
                             self.registerPlugin(thumbnailPluginModule);     
                            deferredThumbnail.resolve();
                        });                                     
                    }                   
                    
                    $.when(deferredBookmark, deferredThumbnail).done(function(){deferredNavigation.resolve()})
                });
            }        

            
            //register document properties plugin.
            var deferredDoc = {};
            if (pluginsConfig.DocProperties === true) {
                deferredDoc = $.Deferred();
                require.async('./Plugins/DocProperties/DocPropertiesPlugin.js', function(docPropertiesPluginModule){
                    self.registerPlugin(docPropertiesPluginModule);
                    deferredDoc.resolve();
                });               
            }

              ///register form plugin;
            /* if (pluginsConfig.Form === true) {
                var pFormPluginModule = require('./Plugins/Form/FormPlugin.js');
                this.registerPlugin(pFormPluginModule);
            }*/

            //register text selection plugin
            var deferredText = {};
            if (pluginsConfig.TextSelection === true) {
                deferredText = $.Deferred();
                require.async('./Plugins/TextSelection/TextSelectionPlugin.js',function(textSelectionPluginModule){
                     self.registerPlugin(textSelectionPluginModule);
                    deferredText.resolve();
                });               
            }
            /*
            //register toolbar and status bar plugin
            if (pluginsConfig.ToolBar === true) {
                var toolBarPluginModule = require('./Plugins/Toolbar/RibbonToolBarPlugin.js');
                this.registerPlugin(toolBarPluginModule);
                var statusBarPluginModule = require('./Plugins/Toolbar/RibbonStatusBar.js');
                this.registerPlugin(statusBarPluginModule);
            }*/

            //register text selection plugin
            var deferredSignature = {};
            if (pluginsConfig.Signature === true) {
                deferredSignature = $.Deferred();
                require.async('./Plugins/Signature/SignaturePlugin.js', function(signaturePluginModule){
                    self.registerPlugin(signaturePluginModule);
                    deferredSignature.resolve();
                });
              
            }

            //register menu bar plugin
            var deferredMenu = {};
            if (pluginsConfig.Menu === true) {
                deferredMenu = $.Deferred();
                require.async('./Plugins/Menu/MenuPlugin.js', function(menuPluginModule){
                    self.registerPlugin(menuPluginModule);
                    deferredMenu.resolve();
                });               
            }

            $.when(deferredAnnot, deferredNavigation, deferredText, deferredDoc, deferredFind, deferredMenu, deferredSignature).done(function(){
                callback();
            })
            /*===end PC===*/
        } else {
            /*===begin Wap===*/
            //Find插件;
            /*if (pluginsConfig.FindTool === true) {
             var FindToolPluginModule = require('./Plugins/FindTool/FindToolPlugin.js');
             this.registerPlugin(FindToolPluginModule);
             }
             var pNavigationPlugin = null;
             if (pluginsConfig.NavigationPanel === true) {
             var NavigationPanelPluginModule = require('./Plugins/NavigationPanel/WapNavigationPanelPlugin.js');
             pNavigationPlugin = this.registerPlugin(NavigationPanelPluginModule);
             }
            */

            //register navigation panel plugin
          /*  var navigationPlugin = null;
            if (pluginsConfig.NavigationPanel === true) {
                var navigationPanelPluginModule = require('./Plugins/NavigationPanel/WapNavigationPanelPlugin.js');
                navigationPlugin = this.registerPlugin(navigationPanelPluginModule);
            }

            //register thumbnail plugin
             if (navigationPlugin != null && pluginsConfig.Thumbnail === true) {
                 var thumbnailPluginModule = require('./Plugins/Thumbnail/ThumbNailPlugin.js');
                 var thumbNailPlugin = this.registerPlugin(thumbnailPluginModule);
                 //添加Thumbnail到Navigation Panel;
                 if (thumbNailPlugin != null) {
                     navigationPlugin.addChildPanel(thumbNailPlugin, true);
                 }
             }

            //register bookmark plugin;
            if (navigationPlugin != null && pluginsConfig.Bookmark === true) {
                var bookmarkPluginModule = require('./Plugins/Bookmark/WapBookmarkPlugin.js');
                var bookmarkPlugin = this.registerPlugin(bookmarkPluginModule);
                if (bookmarkPlugin != null) {
                    navigationPlugin.addChildPanel(bookmarkPlugin, true);
                }
            }

            //register document properties plugin.
            if (navigationPlugin != null && pluginsConfig.DocProperties === true) {
                var docPropertiesPluginModule = require('./Plugins/DocProperties/WapDocPropertiesPlugin.js');
                var docPropertiesNailPlugin = this.registerPlugin(docPropertiesPluginModule);
                if (docPropertiesNailPlugin != null) {
                    navigationPlugin.addChildPanel(docPropertiesNailPlugin, true);
                }
            }*/
            //register text selection plugin
            if (pluginsConfig.FindTool === true) {
                require.async('./Plugins/FindTool/FindToolPlugin.js', function(findToolPluginModule){
                    self.registerPlugin(findToolPluginModule);
                });
                
            }
            if (pluginsConfig.TextSelection === true) {
                require.async('./Plugins/TextSelection/TextSelectionPlugin.js', function(textSelectionPluginModule){
                     self.registerPlugin(textSelectionPluginModule);
                });               
            }
            /*
             //ToolBar插件;
             if (pluginsConfig.ToolBar === true) {
             var pToolBarPluginModule = require('./Plugins/Toolbar/WapRibbonToolbarPlugin.js');;
             this.registerPlugin(pToolBarPluginModule);
             }*/
            /*===end Wap===*/
        }
    };

        /**
         * Disable print for web page.
         * @ignore
         */
        this.disablePrint = function () {
            var css = 'body { display:none; }',
                head = document.head || document.getElementsByTagName('head')[0],
                style = document.createElement('style');

            style.type = 'text/css';
            style.media = 'print';
            if (style.styleSheet) {
                style.styleSheet.cssText = css;
            } else {
                style.appendChild(document.createTextNode(css));
            }

            head.appendChild(style);
        };

        /**
         * @description Check whether the user has permission to download the source PDF file.
         * @return {Boolean} if the user has permission to download the source PDF file, return true, otherwise, return false.
         * @ignore
         */
        /*this.canDownloadPDF = function () {
            return _canDownloadPDF;
        };*/

        /**
         * Set whether the end user can download the PDF file.
         * @param {Boolean} canDownloadPDF
         * @ignore
         */
        /*this.setDownloadPDFPermission = function(canDownloadPDF){
            _canDownloadPDF = canDownloadPDF;
        };*/

        this.getDocPermission = function () {
            return _docPermission;
        };

        /**
         * Set doc permission
         * @param {Integer} permission  doc permission
         * @ignore
         */
        /*this.setDocPermission = function(permission){
            _docPermission = permission;
        };*/
        
        /**
         * Get doc hash
         * @returns {string} hash  doc hash
         * @ignore
         */
        /*this.getDocHash = function () {
            return _docHash;
        };*/
        
        /**
         * Set doc hash
         * @param {string} hash  doc hash
         * @ignore
         */
        /*this.setDocHash = function (docHash) {
            _docHash = docHash;
        };*/

        /**
         * Check whether current document is in trail mode
         * @returns {boolean} return true if current document is in trail mode
         * @ignore
         */
        this.isTrail = function(){
            return _isTrail;
        };

        this.setTrail = function(isTrail){
            _isTrail = isTrail;
        };

        /**
         * 获取session id，主要用来解决safari跨域cookie问题
         * @returns {string} session id
         * @ignore
         */
        this.getSessionId = function(){
            return _sessionId;
        };

        this.setSessionId = function(sessionId){
            _sessionId = sessionId;
        };

        this.getSessionIdAuthHeader = function(){
            return _sessionIdAuthHeader;
        };


        this.getTextManager = function () {
            if (_textManager == null)
                _textManager = new WebPDF.PDFData.Text.TextManager(this);
            return _textManager;
        };

        /**
         * @description Initialize the app instance.
         * @ignore
         */
        this.initInstance = function () {            
            this.registerBaseModule(_.bind(function(){
               this.trigger(WebPDF.EventList.APP_READY, {});
               this.loadDocument();
            }, this))            
        };
        
        this.loadDocument = function(){        
            console.log("loadDocument")
             WebPDF.waiting(this,{});       
             _loadDocument(null, false, Config.defaults.maxManifestRetryCount);
        };
        
        _.bindAll(this, "loadDocument")
        /**
         * @description Add a menu item definition.
         * @ignore
         */
        this.addMenuItem = function (menuItemDefinition) {
            if (menuItemDefinition == null)
                return false;
            var menuItem = new CMenuItem(menuItemDefinition);
            _menuItemList[menuItem.name] = menuItem;
            return true;
        };
        /**
         * @description Get a menu item.
         * @param {String} menuItemName name of the menu item.
         * @return {WebPDF.CMenuItem} menu item.
         * @ignore
         */
        this.getMenuItem = function (menuItemName) {
            return _menuItemList[menuItemName];
        };

        //////////////////////////////////End Command 相关////////////////////////////////////////


        /////////////////////////////////////事件注册相关/////////////////////////////////////
        //MainFrm Event
        /**
         * @description Register a mainframe event handler.
         * @param {WebPDF.Event.IReaderMainFrmEventHandler} mainFrmHandler a instance of mainframe event handler.
         * @return {Boolean} If the registration is successful, return true, otherwise, return false.
         * @ignore
         */
        this.registerMainFrmEventHandler = function (mainFrmHandler) {
            if (!mainFrmHandler)
                return false;
            _mainFrameEventHandlerList.push(mainFrmHandler);
            return true;
        };
        /**
         * @description (MainFrm Event)Unregister a mainframe event handler.
         * @param {WebPDF.Event.IReaderMainFrmEventHandler} mainFrmEventHandler a instance of mainframe event handler.
         * @return {Boolean} If the Unregistration is successful, return true, otherwise, return false.
         * @ignore
         */
        this.unRegisterMainFrmEventHandler = function (mainFrmEventHandler) {
            if (!mainFrmEventHandler)
                return false;
            for (var i = 0; i < _mainFrameEventHandlerList.length; i++) {
                if (_mainFrameEventHandlerList[i] === mainFrmEventHandler) {
                    delete _mainFrameEventHandlerList[i];
                    _mainFrameEventHandlerList.splice(i, 1);
                    return true;
                }
            }
            return false;
        };

        //MousePt Event
        /**
         * @description (MousePt Event)Register a mouse event handler.
         * @param {WebPDF.Event.IReaderMousePtHandler} mousePtHandler a instance of mouse event handler.
         * @return {Boolean} If the registration is successful, return true, otherwise, return false.
         * @ignore
         */
        this.registerMousePtHandler = function (mousePtHandler) {
            if (!mousePtHandler)
                return false;
            this.mousePtHandlerList.push(mousePtHandler);
            return true;
        };
        /**
         * @description Unregister a mouse event handler.
         * @param {WebPDF.Event.IReaderMousePtHandler} mousePtHandler a instance of mouse event handler.
         * @return {Boolean} If the Unregistration is successful, return true, otherwise, return false.
         * @ignore
         */
        this.unRegisterMousePtHandler = function (mousePtHandler) {
            if (!mousePtHandler)
                return false;
            for (var i = 0; i < _mousePtHandlerList.length; i++) {
                if (this.mousePtHandlerList[i] === mousePtHandler) {
                    delete this.mousePtHandlerList[i];
                    this.mousePtHandlerList.splice(i, 1);
                    return true;
                }
            }
            return false;
        };

        /**
         * Load all plugins.
         * @private
         */
        this.loadPlugins = function() {
            $.each(this.pluginList, function (pluginName, plugin) {               
               // try {
                    plugin.init();
               // }
               // catch (ex) {
                 //   console.error(ex);
               // }
                return true;
            });
        }

        /**
         * @description Register a plug-in of web reader.
         * @param {WebPDF.IReaderPlugin} pluginModule a instance of the plug-in module.
         * @return {WebPDF.IReaderPlugin} If the registration is successful, return the plug-in, otherwise, return null.
         * @ignore
         */
        this.registerPlugin = function (pluginModule) {
            if (!pluginModule)
                return null;
            var plugin = pluginModule.createPlugin(this);
            if (plugin == null)
                return null;
            try {
                
                var pluginName = plugin.getPluginName();
                if (this.pluginList[pluginName])
                    $.error("The plugin '" + pluginName + "' has been registered!");
                this.pluginList[pluginName] = plugin;
                plugin.onRegister();
                console.log(pluginName)
            }
            catch (ex) {
                console.error(ex);
                return null;
            }
            return plugin;
        };
        /**
         * @description Get a plug-in object by the name of the plug-in.
         * @param {String} pluginName the name of the plug-in.
         * @return {WebPDF.IReaderPlugin} a plug-in object.
         * @ignore
         */
        this.getPluginByName = function (pluginName) {
            return this.pluginList[pluginName];
        };

        /**
         * @description Get ID of current document.
         * @return {String} ID of current document.
         * @ignore
         */
        this.getFileID = function () {
            return this.options.fileId;
        };
        
        this.getUserName = function(){
            return WebPDF.loginEmail;
        };
        /**
         * @description Get name of current document.
         * @return {String} name of current document.
         * @ignore
         */
        this.getFileName = function () {
            return _fileName;
        };
        /**
         * @description Set name of current document.
         * @return {String} name of current document.
         * @ignore
         */
        this.setFileName = function (fileName) {
            _fileName = fileName;
        };
        /**
         * @description Get the mainframe view.
         mainframe view is the view of the entire page, including top panel,bottom panel, navigation panel and doc view.
         * @return {WebPDF.PDFView.CMainFrame} the mainframe view.
         * @ignore
         */
        this.getMainView = function () {
            return this.mainView;
        };
        /**
         * @description Returns the Document that is currently being displayed by the viewer.
         * @return {WebPDF.IPDFDocument} The PDF document object.
         */
        this.getPDFDoc = function () {
            return this.pdfDoc;
        };

        /**
         * Returns the current PDFDocView object.
         * @returns {WebPDF.PDFView.PDFDocView} The current PDFDocView object.
         */
        this.getDocView = function(){
            return this.getMainView().getDocView();
        };

        /**
         * resize viewer.
         * @param {Number|null|undefined} mainFrameWidth New width of mainframe
         * @param {Number|null|undefined} mainFrameHeight New height of mainframe
         * @ignore
         */
        this.onResize = function (mainFrameWidth, mainFrameHeight) {
            if (this.mainView) {
                this.mainView.onResize(mainFrameWidth, mainFrameHeight);
            }
            this.trigger(WebPDF.EventList.MAINFRAME_RESIZE, {});
        };

        /**
         * @description Register a tool handler of web reader.
         * @param {WebPDF.Event.IReader_ToolHandler} pToolHandler a instance of tool handler.
         * @return {Boolean} If the registration is successful, return true, otherwise, return false.
         * @ignore
         */
        this.registerToolHandler = function (toolHandler) {
            if (!toolHandler)
                return false;
           // try {
                var toolName = toolHandler.getName();
                if (this.toolHandlerList[toolName])
                    $.error("The tool '" + toolName + "' has been registered!");
                this.toolHandlerList[toolName] = toolHandler;
                toolHandler.onInit();
           // }
           // catch (ex) {
             //   console.error(ex);
             //   return false;
           // }
            return true;
        };
        /**
         * @description Set current tool.
         * @param {WebPDF.Tools.IReaderToolHandler} toolHandler the tool handler to set.
         * @ignore
         */
        this.setCurToolHandler = function (toolHandler) {
            if (!toolHandler)
                return;
            var temp = this.curToolHandler;
            if (temp !== toolHandler) {
                if (temp) {
                    temp.onDeactivate();
                }
            }
            this.curToolHandler = toolHandler;
            if (temp !== toolHandler) {
                if(this.curToolHandler){
                    this.curToolHandler.onActivate();
                }
                this.trigger(WebPDF.EventList.TOOL_CHANGED,
                    {
                        oldToolName: temp ? temp.getName() : "",
                        newToolName: this.curToolHandler? this.curToolHandler.getName() : ""
                    }
                );
            }
        };

        /**
         * Set tool by name.
         * @param toolName name of tool to set.
         * @ignore
         */
        this.setCurrentToolByName = function(toolName){
            var curTool = this.getCurToolHandler();
            var tool = this.getToolHandlerByName(toolName);
            if (tool != curTool && tool != null) {
                this.setCurToolHandler(tool);
            }
        };

        /**
         * @description Get current tool handler.
         * @return {WebPDF.Tools.IReaderToolHandler} a instance of tool handler.
         * @ignore
         */
        this.getCurToolHandler = function () {
            return this.curToolHandler;
        };
        /**
         * @description Get tool handler by name.
         * @param {String} toolName name of the tool.
         * @return {WebPDF.Tools.IReaderToolHandler} a instance of tool handler.
         * @ignore
         */
        this.getToolHandlerByName = function (toolName) {
            return this.toolHandlerList[toolName];
        };
        /**
         * Check whether current tool is hand tool.
         * @returns {boolean} return true if current tool is hand tool, otherwise return false.
         * @ignore
         */
        this.isCurrentHandTool = function () {
            var tool = this.getToolHandlerByName(WebPDF.Tools.TOOL_NAME_HAND);
            return  tool === _curToolHandler;
        };

        this.setModified = function(pageView, docView, isModified){
            pageView && pageView.setModified(isModified);
            this.getDocView().setModified(isModified);
        };

        /**
         * get pixels per point.
         * @returns {number} pixels per point.
         * @ignore
         */
        this.getPixelsPerPoint = function () {
            return 96 / 72;
        };

        /**
         * Bind mouse events. this must be called after the viewer has been created.
         * @private
         */
        this.bindMouseEvent = function() {
            /*
            var jqDocViewContainer = $("#" + _mainView.getDocView().getDocViewContainerID());
            if (jqDocViewContainer.length <= 0) {
                $.error('Doc view container is not exist!');
            }
            new MouseBindingHandler(jqDocViewContainer, this).bind();
            var jqMainFrm = $("#" + _mainView.getMainFrameID());
            jqMainFrm.mousedown(function (event) {
            	
                if (event.button == 0 || event.button == 1) {
                    this.onMainFrmLButtonDown(event);
                }
                return true;
            });
            jqMainFrm.mousemove(function (event) {
                this.onMainFrmMouseMove(event);
            });
            jqMainFrm.mouseup(function (event) {
                this.onMainFrmLButtonUp(event);
            });
            jqMainFrm.mouseleave(function (event) {
                this.onMainFrmMouseLeave(event);
            });
            jqMainFrm.mouseout(function (event) {
                this.onMainFrmMouseOut(event);
            });*/
        }

        var mouseEventList = {
            'onLButtonDown': 'onLButtonDown',
            'onLButtonUp': 'onLButtonUp',
            'onLButtonDbClick': 'onLButtonDblClk',
            'onMouseMove': 'onMouseMove',
            'onRButtonDown': 'onRButtonDown',
            'onRButtonUp': 'onRButtonUp',
            'onRButtonDblClk': 'onRButtonDblClk',
            'onMouseWheel': 'onMouseWheel',
            'onMouseOver': 'onMouseOver',
            'onMouseOut': 'onMouseOut',
            'onMouseLeave': 'onMouseLeave',
            'onMouseEnter': 'onMouseEnter',
            'onDoubleTap': 'onDoubleTap',
            'onPinchIn': 'onPinchIn',
            'onPinchOut': 'onPinchOut',
            'onHold': 'onHold'
        };
        $.each(mouseEventList, function (mouseEventName, toolHandlerEventName) {
            this[mouseEventName] = function (event) {
                var isProcessed = false;
                $.each(_mousePtHandlerList, function (index, handler) {
                    isProcessed = handler ? handler[toolHandlerEventName](event) : false;
                    return !isProcessed;
                });
                return isProcessed;
            };
        });

        var mainframeMouseEventList = {
            'onMainFrmLButtonDown': 'onLButtonDown',
            'onMainFrmLButtonUp': 'onLButtonUp',
            'onMainFrmMouseMove': 'onMouseMove',
            'onMainFrmMouseOut': 'onMouseMove',
            'onMainFrmMouseLeave': 'onMouseLeave'
        };
        $.each(mainframeMouseEventList, function (mouseEventName, mainframeMouseEventName) {
            this[mouseEventName] = function (event) {
                var isProcessed = false;
                $.each(_mainFrameEventHandlerList, function (index, handler) {
                    isProcessed = handler ? handler[mainframeMouseEventName](event) : false;
                    return !isProcessed;
                });
                return isProcessed;
            };
        });
    };

    /**
     * Mouse binding handler for doc view.
     * @param jqDocViewContainerDiv JQuery object for doc view.
     * @param {WebPDF.ReaderApp} readerApp The app instance.
     * @constructor
     */
    function MouseBindingHandler(jqDocViewContainerDiv, readerApp) {
        var _jqDocViewContainerDiv = jqDocViewContainerDiv,
            _jqWindow = $("#" + readerApp.getMainFrameId());// $(document),
            var self = this,
            _readerApp = readerApp;
        var _isMouseDown = false;
        var _mouseCapturedObj = null;

        var mouseEventList = {
            'onLButtonDown': ['onLButtonDown' , 'onLButtonDown'],
            'onLButtonUp': ['onLButtonUp' , 'onLButtonUp'],
            'onRButtonDown': ['onRButtonDown' , 'onRButtonDown'],
            'onRButtonUp': ['onRButtonUp' , 'onRButtonUp'],
            'onLButtonDbClick': ['onLButtonDblClk' , 'onLButtonDbClick'],
            'onRButtonDbClick': ['onRButtonDblClk' , 'onRButtonDbClick'],
            'onMouseMove': ['onMouseMove' , 'onMouseMove'],
            'onMouseLeave': ['onMouseLeave' , 'onMouseLeave'],
            'onMouseEnter': ['onMouseEnter' , 'onMouseEnter'],
            'onMouseOver': ['onMouseOver' , 'onMouseOver'],
            'onMouseOut': ['onMouseOut' , 'onMouseOut'],
            'onDoubleTap': ['onDoubleTap', 'onDoubleTap'],
            'onPinchIn': ['onPinchIn', 'onPinchIn'],
            'onPinchOut': ['onPinchOut', 'onPinchOut'],
            'onHold': ['onHold', 'onHold']
        };
        $.each(mouseEventList, function (mouseEventName, data) {
            var toolHandlerEventName = data[0];
            var appEventName = data[1];
            this[mouseEventName] = function (event) {
                var curToolHandler = _readerApp.getCurToolHandler();
                if (!curToolHandler)
                    return;
                if (curToolHandler.isProcessing()) {
                    curToolHandler[toolHandlerEventName](event);
                }
                else {
                    var isProcessed = _readerApp[appEventName](event);
                    //trigger left button down event for current tool handler if the event has not been processed.
                    if (!isProcessed) {
                        curToolHandler[toolHandlerEventName](event);
                    }
                }
            };
        });

        /**
         * Initialize touch events.
         * @private
         */
        function _initTouch() {
           // return;
            //var _oldScale = 0;
            //var current = null;
            //bind gesture
            /*Hammer(_jqDocViewContainerDiv.get(0)).on("pinchout pinchin doubletap hold" // dragstart drag dragend"
                , function (event) {
                //var docView = _readerApp.getMainView().getDocView();
                switch (event.type) {
                    case "doubletap":{
                        this.onDoubleTap(event);
                    }
                        break;
                    case 'pinchout': {
                        this.onPinchOut(event);
                    }
                        break;
                    case 'pinchin': {
                        this.onPinchIn(event);
                    }break;
                    case 'hold':{
                        this.onHold(event);
                    }break;
                    case 'dragstart': {
                        if (event.currentTarget.id != "fx_doc_qrcode_image") {
                            $("#fx_doc_qrcode_image").hide();
                        }
                        if (!event.gesture || (event.gesture.touches != null && event.gesture.touches.length != 1))
                            return;
                        var touch = event.gesture.touches[0];
                        var elem = touch.target;
                        if (WebPDF.Common.isElemInteractive(elem)) {
                            return true;
                        }
                        this.onLButtonDown(touch);
                        _isMouseDown = true;
                        event.preventDefault();
                    }break;
                    case 'drag':{
                        if (!event.gesture || (event.gesture.touches != null && event.gesture.touches.length != 1))
                            return;
                        var touch = event.gesture.touches[0];
                        if (WebPDF.Common.isElemInteractive(touch.target)) {
                            return;
                        }
                        endX = touch.pageX;
                        endY = touch.pageY;
                        this.onMouseMove(touch);
                        event.preventDefault();
                        return true;
                    }break;
                    case 'dragend':{
                        this.onLButtonUp({ pageX: endX, pageY: endY });
                        _isMouseDown = false;
                    }break;
                }
            });*/
/*           var endX,
                endY;*/
            _jqDocViewContainerDiv.off('touchstart touchmove touchend').on(
                'touchstart',
                function (e) {
                  /*  if (e.currentTarget.id != "fx_doc_qrcode_image") {
                        $("#fx_doc_qrcode_image").hide();
                    }
                    if (e.originalEvent.touches != null && e.originalEvent.touches.length != 1)
                        return;
                    var touch = e.originalEvent.touches[0];
                    var elem = touch.target;
                    if (WebPDF.Common.isElemInteractive(elem)) {
                        return true;
                    }
                    this.onLButtonDown(touch);
                    _isMouseDown = true;*/
                   // e.preventDefault();
                }
            ).on(
                'touchmove',
                function (e) {
                   /* if (e.originalEvent.touches != null && e.originalEvent.touches.length != 1)
                        return;
                    var touch = e.originalEvent.touches[0];
                    if (WebPDF.Common.isElemInteractive(touch.target)) {
                        return;
                    }
                    endX = touch.pageX;
                    endY = touch.pageY;
                    this.onMouseMove(touch);*/
                   // e.preventDefault();
                    return true;
                }
            ).on(
                'touchend',
                function () {
                   /*this.onLButtonUp({ pageX: endX, pageY: endY });
                    _isMouseDown = false;*/
                }
            );
        }

        this.bind = function () {

            if ($.support.touch) {
                _initTouch();
                return;
            }
            
            if (WebPDF.WindowMouseEventBind) {
            	return;
            }
            WebPDF.WindowMouseEventBind = true;
            
            _jqWindow.mousedown(function (event) {
                var parent = $(event.target).parents("[fxmouse='false']");
                if (parent && parent.length > 0) {
                    return;
                }
                
                //left mouse button down
                var elem = event.target;
                if (event.button == 0 || event.button == 1) {

                    var docView = _readerApp.getMainView().getDocView();
                    var docViewRect = docView.getDocViewClientRect();
                    if (!WebPDF.RectUtils.ptInRect(docViewRect, event.pageX, event.pageY))
                        return true;

                    if (WebPDF.Common.isElemInteractive(readerApp,elem)) {
                        return true;
                    }

                    WebPDF.Common.preventDefaults(event, true);

                    if (elem.setCapture) {
                        _mouseCapturedObj = elem;
                        _mouseCapturedObj.setCapture();
                    } else if (window.captureEvents) {
                        window.captureEvents(Event.MOUSEUP);
                    }
                    //Fix bug for blur events of some element can not be triggered.

                    //原生滚动条的时候对doc view调用focus无法使当前元素失去焦点
                    //如果event.target有fxblur="false" 标记，即不需要触发blur事件
                    var parent = $(event.target).parents("[fxblur='false']");
    				if (!parent || parent.length <= 0) {
    					document.activeElement && $.isFunction(document.activeElement.blur)  && document.activeElement.blur();
                        document.getElementById(docView.getDocViewContainerID()).focus();
    				}

                    this.onLButtonDown(event);
                    _isMouseDown = true;
                }
                //right mouse down
                else if (event.button == 2 || event.button == 3) {
                    this.onRButtonDown(event);
                }
                return true;
            });
            _jqWindow.mousemove(function (event) {
                var parent = $(event.target).parents("[fxMouse='false']");
                if (parent && parent.length > 0) {
                    return;
                }
                
                this.onMouseMove(event);
                return true;
            });
            _jqWindow.mouseup(function (event) {
                var parent = $(event.target).parents("[fxmouse='false']");
                if (parent && parent.length > 0) {
                    return;
                }
                
                if (!_isMouseDown) {
                    if (WebPDF.Common.isElemInteractive(readerApp,event.target)) {
                        return true;
                    }
                }
                if (event.button == 0 || event.button == 1) {
                    if (_mouseCapturedObj && _mouseCapturedObj.releaseCapture) {
                        _mouseCapturedObj.releaseCapture();
                    } else if (window.releaseEvents) {
                        window.releaseEvents(Event.MOUSEUP);
                    }
                    this.onLButtonUp(event);
                }
                else if (event.button == 2 || event.button == 3) {
                    this.onRButtonUp(event);
                }
                _isMouseDown = false;
                _mouseCapturedObj = null;
                return true;
            });
            _jqWindow.dblclick(function (event) {
                var parent = $(event.target).parents("[fxmouse='false']");
                if (parent && parent.length > 0) {
                    return;
                }
                
                if (WebPDF.Common.isElemInteractive(readerApp,event.target)) {
                    return true;
                }
                WebPDF.Common.preventDefaults(event, true);
                if (event.button == 0 || event.button == 1) {
                    this.onLButtonDbClick(event);
                }
                else if (event.button == 2 || event.button == 3) {
                    this.onRButtonDbClick(event);
                }
                return true;
            });
            _jqWindow.mouseover(function (event) {
                var parent = $(event.target).parents("[fxmouse='false']");
                if (parent && parent.length > 0) {
                    return;
                }
                
                if (_isMouseDown) {
                    var jqTarget = $(event.target);
                    if(jqTarget.hasClass("fwrJspTrack") ) {
                        this.onLButtonUp(event);
                        return false;
                    }
                }
                this.onMouseOver(event);
            });
            _jqWindow.mouseout(function (event) {
                var parent = $(event.target).parents("[fxmouse='false']");
                if (parent && parent.length > 0) {
                    return;
                }
                this.onMouseOut(event);
            });
            _jqWindow.mouseleave(function (event) {
                var parent = $(event.target).parents("[fxmouse='false']");
                if (parent && parent.length > 0) {
                    return;
                }
                this.onMouseLeave(event);
            });
            _jqWindow.mouseenter(function (event) {
                var parent = $(event.target).parents("[fxmouse='false']");
                if (parent && parent.length > 0) {
                    return;
                }
                this.onMouseEnter(event);
            });
        };
    }
    _.extend(ReaderApp.prototype, Backbone.Events)
    module.exports = ReaderApp;
});